package com.code.test.second.array;

import java.util.Arrays;

public class SCode27 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 2, 3, 5, 6, 2};
        int index = removeWithLog(arr, 2);
        System.out.println(index);
        System.out.println(Arrays.toString(arr));

    }

    /**
     * 不只是统计被删除数量，而是要将元素移除
     */
    public static int removeEle(int[] nums, int target) {
        int len = nums.length;
        //不能使用额外空间
        //记录删除的元素数量
        int count = 0;
        for (int i = 0; i < len; i++) {
            if (nums[i] == target) {
                //如果i这个元素等于目标值，则把后面每个元素都往前移动
                //为什么是j=i+1,因为是当前是把当前元素的后面一个开始覆盖自己
                //所以 j=i+1,j-1=i+1-1=i，相当于 nums[i]=nums[i+1]
                for (int j = i + 1; j < len; j++) {
                    //比如idx=3，nums[2] = nums[1]
                    nums[j - 1] = nums[j];
                }
                len--;
                count++;
            }
        }
        return nums.length - count;
    }

    /**
     * https://www.cnblogs.com/lulixiu1999/p/17950864
     */
    public static int removeEleByFast(int[] nums, int target) {
        int slow = 0;
        int len = nums.length;
        for (int fast = 0; fast < len; fast++) {
            //如果快指针位置的元素不等于要删除的元素
            if (nums[fast] != target) {
                /**
                 * 快慢指针一直往后遍历，当遇到要删除的元素时:快指针往后++，慢指针停下来,所以慢指针等于新的数组的大小
                 *
                 * 当快指针遇到不是要删除的元素时，就将当前元素往前移
                 * 假设遇到一个元素是要删除的，快指针不动，继续++，然后遇到不是要删除的元素，则把这个元素覆盖给前一个元素
                 * 重点是：当遇到要删除的元素，保持不动，让后面的来覆盖他，所以这个元素就被删除了
                 */
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }

    public static int removeElePoint(int[] nums, int value) {
        int slow = 0;
        int fast = 0;
        while (fast < nums.length) {
            if (nums[fast] != value) {
                nums[slow] = nums[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }

    public static int remove(int[] nums, int value) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            if (nums[left] == value) {
                nums[left] = nums[right];
                right--;
                //注意这里,left没变动，而是把右边元素赋值过来，所以可以兼容right指针与val相等的情况
                //因为赋值过来是相同的，又会继续匹配，又把右边赋值过来，所以即便后面全是等于val的，left也没变动，就等于正确的数量，
            } else {
                // 这里兼容了right指针指向的值与val相等的情况
                //只有跟目标不一样，才会++，才是正确计数
                left++;
            }
        }
        return left;
    }

    public static int removeWithLog(int[] nums, int value) {
        //采用双指针
        int slow = 0;
        int fast = 0;
        for (; fast < nums.length; fast++) {
            if (nums[fast] != value) {
                //快指针走得比较快
                nums[slow] = nums[fast];
                slow++;
            } else {
                //当碰到与目标值一致，则跳过，等待下一轮来覆盖
            }
        }
        return slow;
    }
}
